package com.sjx.onelinecord.http

import android.content.Context
import android.os.Environment
import android.util.Log
import android.widget.Toast
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit

/**
 * 对于安卓开发来说，一个网络请求是用POST还是GET，取决于接口文档上面接口的声明
 * 是GET还是POST，POST和GET请求都有同步异步的区别。POST有同步方式的请求，也有
 * 异步方式的请求，GET请求亦然。
 * GET请求的请求参数以？key=value的形式传给后台接口入参
 * POST请求以.post(body)的形式入参
 * 同步请求发送请求时要手动开一个子线程，异步请求会自动开一个子线程，无需手动Thread(Runnable {...}.start()
 */

object HiOkHttp {
    private val BASE_URL = "http://123.56.232.18:8080/serverdemo"

    /*
        初始化OkHttp
     */
    val client: OkHttpClient = OkHttpClient.Builder() //builder构造者设计模式
            .connectTimeout(10, TimeUnit.SECONDS) //连接超时时间
            .readTimeout(10, TimeUnit.SECONDS) //读取后台接口数据超时时间
            .writeTimeout(10, TimeUnit.SECONDS) //往后台接口写数据超时时间
            .build()

    //Android分为主线程和子线程
    //主线程就是APP一启动后，咱们android framework层会启动一个线程，主线程（UI线程）
    //子线程 --new Thread().start()
    fun get() { //url就是网络请求接口路径
        Thread(Runnable {
            //构造请求体
            val request: Request = Request.Builder()
                    .url("$BASE_URL/user/query?userId=1600922269")
                    .build()
            // 构造请求对象
            val call: Call = client.newCall(request)
            //发起同步请求execute() -- execute()是同步执行的
            val response: Response = call.execute()
            //因为是同步请求，只有execute()方法执行完之后才能执行下面的代码
            val body: String? = response.body?.string()
            Log.i("TAG", "get response : $body")
        }).start()
    }

    fun getAsync() { //url就是网络请求接口路径
        //构造请求体
        val request: Request = Request.Builder()
                .url("$BASE_URL/user/query?userId=1600922269")
                .build()
        // 构造请求对象
        val call: Call = client.newCall(request)
        //发起同步请求execute() -- execute()是同步执行的
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                Log.i("OKHTTP", "get response failure: ${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                val body: String? = response.body?.string()
                Log.i("OKHTTP", "get response successful: $body")
            }

        })
    }

    /**
     * POST同步请求，使用的表单提交
     */
    fun post() {
        val body = FormBody.Builder()
                .add("userId", "1600932269")
                .add("tagId", "71")
                .build()
        val request =
                Request.Builder().url("$BASE_URL/tag/toggleTagFollow")
                        .post(body)
                        .build()
        val call = client.newCall(request)
        Thread(Runnable {
            val response = call.execute()
            Log.i("OKHTTP", "post response:${response.body?.string()}")
        }).start()
    }

    /**
     * POST异步请求，使用的表单提交，表单提交就是像下面.add("key","value").add("key2","value2")
     * 一样，具体百度，俺也不太清楚
     */

    fun postAsync() {
        val body = FormBody.Builder()
                .add("userId", "1600932269")
                .add("tagId", "71")
                .build()
        val request =
                Request.Builder().url("$BASE_URL/tag/toggleTagFollow")
                        .post(body)
                        .build()
        val call = client.newCall(request)
        val response = call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                Log.i("OKHTTP", "post onFailure:${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                Log.i("OKHTTP", "post response:${response.body?.string()}")
            }
        })
    }

    /**
     * POST异步请求【多表单文件上传】，在Android6.0及以后，读取外部存储卡的文件都是需要
     * 动态权限申请。下面这个post异步请求多表单文件上传只是一个事例，并没有提供实际的接口
     * 供练习，如果以后公司项目有需求是POST异步请求【多表单文件上传】按照下面代码模拟即可。
     */
    fun postAsyncMultipart(context: Context) {
        val file = File(Environment.getExternalStorageDirectory(), "1.png")
        if (!file.exists()) {
            Toast.makeText(context, "file haven't exists", Toast.LENGTH_LONG).show()
            //注意if语句中的return代表直接退出函数，回到函数调用处，不会再执行下面的语句。
            //该if语句如果文件存在的话就不会进入if语句内部，也就不会执行return，就可以执行if语句之后的逻辑。
            return
        }
        val body = MultipartBody.Builder()
                .addFormDataPart("key", "value")
                .addFormDataPart("key2", "value2")
                .addFormDataPart("file", "file.png",
                        RequestBody.create("application/octet-stream"
                                .toMediaType(), file)).build()

        val request =
                Request.Builder().url("接口是需要支持文件上传才可以使用的")
                        .post(body)
                        .build()

        val call = client.newCall(request)
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                Log.i("OKHTTP", "postAsyncMultipart onFailure:${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                Log.i("OKHTTP", "postAsyncMultipart onResponse:${response.body?.string()}")
            }
        })

    }
}



